#include "StdAfx.h"
#include "Model.h"
#include <algorithm>

void CGraphBase::SetNodeIdByXY( int id, float x, float y, CRect rectRange ){
	float rateX = rectRange.Width() / 10000.0f;
	float rateY = rectRange.Height() / 10000.0f;

	if( _mapNodeInfo.find( id ) != _mapNodeInfo.end() )
	{
		_mapNodeInfo[id]._x = x / rateX;
		_mapNodeInfo[id]._y = y / rateY;
	}
}

int CGraphBase::GetNodeIdByXY( float x, float y, CRect rectRange ){
	
	float rateX = rectRange.Width() / 10000.0f;
	float rateY = rectRange.Height() / 10000.0f;
	int r = 10;

	std::map< int, NodeInfo >::const_iterator itr;
	for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ ){
		CRect rect(	rectRange.left + itr->second._x * rateX - r, 
						 rectRange.top + itr->second._y * rateY - r, 
						rectRange.left + itr->second._x * rateX + r, 
						 rectRange.top + itr->second._y * rateY + r);
		CPoint pt( x, y );
		if( rect.PtInRect( pt ) )
			return itr->first;
	}
	return -1;
}

void CGraphBase::Clear()
{
	_mapNodeInfo.clear();
	_edges.clear();
}

void CGraphBase::DeleteNode( int id )
{
	{
		std::map< int, NodeInfo >::iterator itr;
		for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ ){
			if( id == itr->first )
				break;
		}

		if( itr != _mapNodeInfo.end() )
			_mapNodeInfo.erase( itr );
	}

	while( true )
	{
		std::vector< Edge >::iterator itr;
		for( itr = _edges.begin(); itr != _edges.end(); itr++ ){
			if( itr->_from == id || itr->_to == id ){
				break;
			}
		}

		if( itr == _edges.end() )
			break;

		_edges.erase( itr );
	}
}

void CGraphBase::AddNodeByXY( float x, float y,  CRect rectRange ){
	std::map< int, NodeInfo >::const_iterator itr;
	int newId = 0;
	for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ ){
		if( newId < itr->first )
			newId = itr->first;
	}
	newId++;

	AddEdge( newId, -1 );
	SetNodeIdByXY( newId, x, y, rectRange );

}

void CGraphBase::AddEdge( int from, int to ){
	if( from != -1 && this->_mapNodeInfo.find( from ) == this->_mapNodeInfo.end() ){
		NodeInfo ni;
		ni._id = from;

		if( 100 + from * 400 < 10000 )
			ni._x = 100 + from * 400;
		_mapNodeInfo[ from ] = ni;
	}

	if( to != -1 && this->_mapNodeInfo.find( to ) == this->_mapNodeInfo.end() ){
		NodeInfo ni;
		ni._id = to;
		if( 100 + to * 400 < 10000 )
			ni._x = 100 + to * 400;
		_mapNodeInfo[ to ] = ni;
	}

	if( from == -1 || to == -1 ){
		return;
	}

	_mapNodeInfo[ from ]._outputs.push_back( to );
	_mapNodeInfo[ to ]._inputs.push_back( from );

	Edge e;
	e._from = from;
	e._to = to;

	_edges.push_back( e );
};

bool CGraphBase::ParseString( std::string str )
{
	// format [ firstNodeId, lastNodeId, (startNodeId, endNodeId) , (startNodeId, endNodeId) , ...]
	// sample
	// "[1,5,(1,2)(2,3)(3,4)(4,5)(2,4)(3,5)]"

//	this->Clear();
	_mapNodeInfo.clear();
	_edges.clear();

	const char* p = str.c_str();

	if( sscanf( p, "[%d,%d,", &_firstNodeId, &_lastNodeId) != 2 ){
		::AfxMessageBox("parse error");
	}

	TRACE("[Parse] edge %d -> %d\n", _firstNodeId, _lastNodeId );

	while( strstr( p, "(") != 0 && strstr( p, ")") != 0 ){
		const char *pL = strstr( p, "(");
		const char *pR = strstr( p, ")");

		if( pR > pL ){
			int idFrom(0), idTo(0);
			if( sscanf( pL, "(%d,%d)", &idFrom, &idTo) == 2 ){
				AddEdge( idFrom, idTo );
//				TRACE("[Parse] edge %d -> %d\n", idFrom, idTo );
			}
		}

		p = pR + 1;
	}
	return true;
}

int CGraphBase::CalculateRouteCount(){

	if( _firstNodeId == -1 || _lastNodeId == -1 )
		return -1;

	std::vector<int> vectNode; 
	std::vector<Edge> vectScannedEdges; 
   int iTotalRoute = 0; 
   int iRestRoute = 0;

   vectNode.push_back( _firstNodeId );

	while( !CalculateRouteCount_Step( vectNode, vectScannedEdges, iTotalRoute, iRestRoute ) )
	{}

	return iTotalRoute;
}

bool CGraphBase::CalculateRouteCount_Step( std::vector<int>& vectNode, 
										   std::vector<Edge>& vectScannedEdges, 
										   int& iTotalRoute, 
										   int& iRestRoute )
{
	for( int k=0; k<vectNode.size();k++){
		TRACE("%d ",vectNode[k] );
	}

	TRACE(" -> ");

	std::vector<int> vectTempNode = vectNode;

	for( int i=0; i<vectTempNode.size();i++){

		// check
		bool bCanGoNext = true;
		{
			for( int j=0; j<this->_mapNodeInfo[ vectTempNode[i] ]._inputs.size();j++){
				int input = this->_mapNodeInfo[ vectTempNode[i] ]._inputs[j];

				if( std::find( vectScannedEdges.begin(), vectScannedEdges.end(),Edge( input, vectTempNode[i] ) ) ==
					vectScannedEdges.end() )
				{
					bCanGoNext = false;
					break;
				}
			}

			if( bCanGoNext == false )
			{
				continue;
			}
		}

		// go next
		{
			iRestRoute = iRestRoute + this->_mapNodeInfo[ vectTempNode[i] ]._inputs.size();

			if( iRestRoute < this->_mapNodeInfo[ vectTempNode[i] ]._outputs.size() )
			{
				iTotalRoute = iTotalRoute + this->_mapNodeInfo[ vectTempNode[i] ]._outputs.size() - iRestRoute;
				iRestRoute = 0;
			}
			else
			{
				iRestRoute -= this->_mapNodeInfo[ vectTempNode[i] ]._outputs.size();
			}

			for( int j=0; j<this->_mapNodeInfo[ vectTempNode[i] ]._outputs.size();j++){
				vectScannedEdges.push_back( Edge( vectTempNode[i], _mapNodeInfo[ vectTempNode[i] ]._outputs[j] ) );

				if( std::find( vectNode.begin(), vectNode.end(), _mapNodeInfo[ vectTempNode[i] ]._outputs[j] ) ==
					vectNode.end() &&
					vectTempNode[i] != _lastNodeId){
						vectNode.push_back(_mapNodeInfo[ vectTempNode[i] ]._outputs[j]);
				}
			}

			vectNode.erase( std::find( vectNode.begin(), vectNode.end(), vectTempNode[i] ) );
		}
	}

	for( int k=0; k<vectNode.size();k++){
		TRACE("%d ",vectNode[k] );
	}
	TRACE(" \n ");

	if( vectNode.size() == 0 )
		return true;

	return false;
}

void CMyGraph::PaintEdgeConnecting( CDC* pDC, int connectingFromId, int x, int y, CRect rectRange ){
	float rateX = rectRange.Width() / 10000.0f;
	float rateY = rectRange.Height() / 10000.0f;

	pDC->MoveTo( rectRange.left + _mapNodeInfo[ connectingFromId ]._x * rateX , 
					rectRange.top + _mapNodeInfo[ connectingFromId ]._y * rateY );
	pDC->LineTo( rectRange.left + x, 
					rectRange.top + y);
}

void CMyGraph::DrawTriangle( CDC* pDC, CRect rectRange, int from, int to ){
	float rateX = rectRange.Width() / 10000.0f;
	float rateY = rectRange.Height() / 10000.0f;

	float k = 300.0f / sqrt( pow( (_mapNodeInfo[ from ]._x - _mapNodeInfo[ to ]._x), 2 ) + 
		pow( (_mapNodeInfo[ from ]._y - _mapNodeInfo[ to ]._y), 2 ) );

	int x = _mapNodeInfo[ to ]._x + ( _mapNodeInfo[ from ]._x - _mapNodeInfo[ to ]._x ) * k;
	int y = _mapNodeInfo[ to ]._y + ( _mapNodeInfo[ from ]._y - _mapNodeInfo[ to ]._y ) * k;

	CPen p(PS_SOLID, 4, RGB(0, 0, 0));
    CPen* oldp=pDC->SelectObject(&p);

	pDC->MoveTo( rectRange.left + x * rateX , 
					rectRange.top + y * rateY );
	pDC->LineTo( rectRange.left + _mapNodeInfo[ to ]._x * rateX , 
					rectRange.top + _mapNodeInfo[ to ]._y * rateY );

	pDC->SelectObject(oldp);
}

void CMyGraph::PaintToDC( CDC* pDC, CRect rectRange ){
	float rateX = rectRange.Width() / 10000.0f;
	float rateY = rectRange.Height() / 10000.0f;

	for( size_t i=0; i<_edges.size(); i++ ){
		pDC->MoveTo( rectRange.left + _mapNodeInfo[ _edges[i]._from ]._x * rateX , 
					 rectRange.top + _mapNodeInfo[ _edges[i]._from ]._y * rateY );
		pDC->LineTo( rectRange.left + _mapNodeInfo[ _edges[i]._to ]._x * rateX , 
					 rectRange.top + _mapNodeInfo[ _edges[i]._to ]._y * rateY );

		DrawTriangle( pDC, rectRange, _edges[i]._from, _edges[i]._to );
	}

	int r = 10;

	CBrush myBrushEllipseBlack;
	myBrushEllipseBlack.CreateSolidBrush(RGB(0,0,0));

	CBrush myBrushEllipseWhite;
	myBrushEllipseWhite.CreateSolidBrush(RGB(155,155,155));
	
	CBrush* pOldBrush;
	pOldBrush=pDC->SelectObject(&myBrushEllipseWhite);
	

	pDC->SetBkMode( TRANSPARENT );

	CFont* pOldFont = pDC->SelectObject(::AfxGetApp()->GetMainWnd()->GetFont());

	std::map< int, NodeInfo >::const_iterator itr;
	for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ ){

		if ( itr->second.an.marked )
			pDC->SelectObject(&myBrushEllipseBlack);
		else
			pDC->SelectObject(&myBrushEllipseWhite);

		pDC->Ellipse(	rectRange.left + itr->second._x * rateX - r, 
						 rectRange.top + itr->second._y * rateY - r, 
						rectRange.left + itr->second._x * rateX + r, 
						 rectRange.top + itr->second._y * rateY + r);

		CRect rect(	rectRange.left + itr->second._x * rateX - r, 
			rectRange.top + itr->second._y * rateY - r, 
			rectRange.left + itr->second._x * rateX + r, 
			rectRange.top + itr->second._y * rateY + r);
		CString str;

		str.Format( "%d", /*0 - 1 + */ itr->first );
		pDC->SetTextColor( RGB( 255, 255, 0 ) );
		pDC->DrawText( str, rect, DT_CENTER | DT_VCENTER );

		// draw ATWLE info
		pDC->SetTextColor( RGB( 0, 0, 0 ) );
		rect.right += 100;

		//str.Format( "es:%d", itr->second.an.es );
		//rect.OffsetRect( CSize(0,r*2) );
		//pDC->DrawText( str, rect, DT_LEFT | DT_VCENTER );

		//str.Format( "marked:%s", itr->second.an.marked ? "true" : "false" );
		//rect.OffsetRect( CSize(0,15) );
		//pDC->DrawText( str, rect, DT_LEFT | DT_VCENTER );

		/*
		str.Format( "tag:%d", itr->second.an.tag );
		rect.OffsetRect( CSize(0,15) );
		pDC->DrawText( str, rect, DT_LEFT | DT_VCENTER );

		str.Format( "is_leader:%s", itr->second.an.is_leader ? "true" : "false" );
		rect.OffsetRect( CSize(0,15) );
		pDC->DrawText( str, rect, DT_LEFT | DT_VCENTER );

		str.Format( "finished:%s", itr->second.an.finished ? "true" : "false" );
		rect.OffsetRect( CSize(0,15) );
		pDC->DrawText( str, rect, DT_LEFT | DT_VCENTER );
		*/

		str.Format( "clock:%d", itr->second.schd.clock );
		rect.OffsetRect( CSize(0,15) );
		pDC->DrawText( str, rect, DT_LEFT | DT_VCENTER );

//		pDC->TextOut(rectRange.left + itr->second._x * rateX - r, 
//						 rectRange.top + itr->second._y * rateY - r, str );
	}

	pDC->SelectObject( pOldFont );

	pDC->SelectObject(pOldBrush);

};

bool CMyGraph::UpdateNodeInfo(){

	// TODO
	
	std::map< int, NodeInfo >	_mapNodeInfoNew = _mapNodeInfo;
	
	std::map< int, NodeInfo >::const_iterator itr = _mapNodeInfoNew.begin();
	for( ; itr != _mapNodeInfoNew.end(); itr++ ){

		if( itr->second._bFixed )
			continue;

		float plusForceX(0), plusForceY(0);
		{
			for( size_t i=0; i<itr->second._inputs.size(); i++ ){
			}
		}

		float minusForceX(0), minusForceY(0);
		{
			float max = 10000.0f;


			std::map< int, NodeInfo >::const_iterator otherItr = _mapNodeInfo.begin();
			for( ; otherItr != _mapNodeInfo.end(); otherItr++ ){
				if( otherItr->second._id != itr->second._id ){
					float d = sqrt( (otherItr->second._x - _mapNodeInfo[itr->second._id]._x) * (otherItr->second._x - _mapNodeInfo[itr->second._id]._x) + 
									(otherItr->second._y - _mapNodeInfo[itr->second._id]._y) * (otherItr->second._y - _mapNodeInfo[itr->second._id]._y)  );
					if( d < max ){
						minusForceX = minusForceX - log( d/max ) * (otherItr->second._x - itr->second._x) / d;
						minusForceY = minusForceY - log( d/max ) * (otherItr->second._y - itr->second._y) / d;
					}
				}
			}
		}

		float forceX = plusForceX + minusForceX;
		float forceY = plusForceY + minusForceY;

	}

	return true;
};

std::vector<int> CGraphBase::N( const NodeInfo& ni ) const{
	std::vector<int> vectNeighbors;
	std::vector< Edge >::const_iterator itr;
	for ( itr = _edges.begin(); itr != _edges.end(); itr++ )
	{
		if( itr->_from == ni._id )
		{
			if( std::find( vectNeighbors.begin(), vectNeighbors.end(), itr->_to) == vectNeighbors.end() )
				vectNeighbors.push_back( itr->_to );
		}
		else if( itr->_to == ni._id )
		{
			if( std::find( vectNeighbors.begin(), vectNeighbors.end(), itr->_from) == vectNeighbors.end() )
				vectNeighbors.push_back( itr->_from );
		}
	}

	return vectNeighbors;
}

std::vector<int> CGraphBase::U( const NodeInfo& ni ) const{
	std::vector<int> vectNeighbors = N( ni );
	vectNeighbors.push_back( ni._id );

	return vectNeighbors;
}

bool CGraphBase::Clean( const NodeInfo& ni ) const{
	if ( ni.an.es == 0 &&
		 ni.an.tag == 0 &&
		 ni.an.marked == false &&
		 ni.an.is_leader == false &&
		 ni.an.finished == false )
	{
		return true;
	}
	return false;
}

bool CGraphBase::Valid( const NodeInfo& ni ) const{

	bool bCheck_a = true;
	if ( !ni.an.marked )
	{
		if ( ni.an.tag == 0 )
			bCheck_a = true;
		else
			bCheck_a = false;
	}

	bool bCheck_b = true;
	bCheck_b = (Parents(ni).size() <= 1);

	bool bCheck_c = true;
	if ( ni.an.marked )
	{
		if ( 1 + Chldrn(ni).size() >= N(ni).size() )
			bCheck_c = true;
		else
			bCheck_c = false;
	}

	bool bCheck_d = true;
	if ( ni.an.marked )
	{
		std::vector<int> vectNeighbors = N( ni );
		for ( size_t i=0; i<vectNeighbors.size(); i++ )
		{
			if ( !_mapNodeInfo.find( vectNeighbors[i] )->second.an.marked )
			{
				std::vector<int> vectParents = Parents(ni);

				if ( vectParents.size() > 0 && vectParents[0] == _mapNodeInfo.find( vectNeighbors[i] )->second._id )
				{
				}
				else
				{
					bCheck_d = false;
				}

			}
		}

	}

	bool bCheck_e = true;
	if ( ni.an.is_leader )
	{
		if ( ni.an.marked )
			bCheck_e = true;
		else
			bCheck_e = false;
	}

	bool bCheck_f = true;
	if ( ni.an.is_leader )
	{
		if ( Parents(ni).size() == 0 )
			bCheck_f = true;
		else
			bCheck_f = false;
	}

	bool bCheck_g = true;
	if ( ni.an.finished )
	{
		if ( Finished(ni) )
			bCheck_g = true;
		else
			bCheck_g = false;
	}

	return	bCheck_a &&
			bCheck_b &&
			bCheck_c &&
			bCheck_d &&
			bCheck_e &&
			bCheck_f &&
			bCheck_g;
}


bool CGraphBase::Clear( const NodeInfo& ni ) const{
	bool bAllNeighborErrorZero = true;
	std::vector<int> vectNeighbors = U( ni );
	for ( size_t i=0; i<vectNeighbors.size(); i++ )
	{
		if ( _mapNodeInfo.find( vectNeighbors[i] )->second.an.es != 0 )
		{
			bAllNeighborErrorZero = false;
			break;
		}
	}

	if ( Valid(ni) && bAllNeighborErrorZero )
	{
		return true;
	}
	return false;
}

bool CGraphBase::Error( const NodeInfo& ni ) const{

	std::vector<int> vectNeighbors = U( ni );

	bool bAllNeighborsESZero = true;
	for(size_t i=0; i<vectNeighbors.size(); i++ )
	{
		if ( _mapNodeInfo.find(vectNeighbors[i])->second.an.es != 0 )
		{
			bAllNeighborsESZero = false;
			break;
		}
	}
	if ( (!Valid(ni)) && bAllNeighborsESZero ) 
	{
		return true;
	}


	bool bExistNeighborsESTwo = false;
	for(size_t i=0; i<vectNeighbors.size(); i++ )
	{
		if ( _mapNodeInfo.find(vectNeighbors[i])->second.an.es == 2 )
		{
			bExistNeighborsESTwo = true;
			break;
		}
	}
	if( (!Clean(ni)) && ( ni.an.es == 1 || bExistNeighborsESTwo ) )
	{
		return true;
	}


	return false;
}

int CGraphBase::Delta_Tag( const NodeInfo& ni1, const NodeInfo& ni2 ) const{
	if ( ni1.an.tag >= ni2.an.tag )
	{
		return (ni1.an.tag - ni2.an.tag);
	}
	else
	{
		return (ni1.an.tag - ni2.an.tag + 5 );
	}
}

int CGraphBase::Delta_ES( const NodeInfo& ni1, const NodeInfo& ni2 ) const{
	if ( ni1.an.es >= ni2.an.es )
	{
		return (ni1.an.es - ni2.an.es);
	}
	else
	{
		return (ni1.an.es - ni2.an.es + 3 );
	}
}

std::vector<int> CGraphBase::Chldrn( const NodeInfo& ni ) const
{
	std::vector<int> vectNeighbors = N( ni );
	std::vector<int> vectChildren;

	for( size_t i=0; i<vectNeighbors.size(); i++ )
	{
		int delta = Delta_Tag( _mapNodeInfo.find( vectNeighbors[i] )->second, ni );
		if ( delta == 1 || delta == 2)
		{
			vectChildren.push_back( vectNeighbors[i] );
		}
	}

	return vectChildren;
}

std::vector<int> CGraphBase::Parents( const NodeInfo& ni ) const
{
	std::vector<int> vectNeighbors = N( ni );
	std::vector<int> vectParents;

	for( size_t i=0; i<vectNeighbors.size(); i++ )
	{
		int delta = Delta_Tag( _mapNodeInfo.find( vectNeighbors[i] )->second, ni );
		if ( delta == 3 || delta == 4)
		{
			vectParents.push_back( vectNeighbors[i] );
		}
	}

	return vectParents;
}

bool CGraphBase::Is_Child( const NodeInfo& ni ) const
{
	std::vector<int> vectParents = Parents(ni);

	return vectParents.size() > 0 ;
}

bool CGraphBase::Finished( const NodeInfo& ni ) const
{
	std::vector<int> vectParents = Parents(ni);

	if ( ni.an.is_leader ||
		(vectParents.size()>0 && 
		 _mapNodeInfo.find(vectParents[0])->second.an.finished &&
		 ni.an.tag == 2 + _mapNodeInfo.find(vectParents[0])->second.an.tag ) )
	{
		return true;
	}

	return false;
}

bool CGraphBase::Can_Reset( const NodeInfo& ni ) const{

	if ( Error(ni) )
	{
		return true;
	}

	std::vector<int> vectNeighbors = N( ni );
	for ( size_t i=0; i<vectNeighbors.size(); i++ )
	{
		if ( _mapNodeInfo.find( vectNeighbors[i] )->second.an.es == 1 )
		{
			return true;
		}
	}

	return false;
}

bool CGraphBase::Can_Inc_Err_St( const NodeInfo& ni ) const{

	bool bAllNeighborsInZeroOrOne = true;
	std::vector<int> vectNeighbors = N( ni );
	for(size_t i=0; i<vectNeighbors.size(); i++ )
	{
		int delta = Delta_ES(_mapNodeInfo.find(vectNeighbors[i])->second, ni );
		if ( delta !=0 && delta != 1)
		{
			bAllNeighborsInZeroOrOne = false;
			break;
		}
	}

	if ( (ni.an.es == 1 || ni.an.es == 2) && bAllNeighborsInZeroOrOne )
	{
		return true;
	}

	return false;
}

bool CGraphBase::IsA1( const NodeInfo& ni ) const{
	return Can_Reset(ni);
}

bool CGraphBase::IsA2( const NodeInfo& ni ) const{
	return Can_Inc_Err_St(ni);
}

bool CGraphBase::IsA3( const NodeInfo& ni ) const{

	bool bAllChildrenTagTwo = true;
	std::vector<int> vectChildren = Chldrn( ni );
	for( size_t i=0; i<vectChildren.size(); i++ ){
		if ( 2 != _mapNodeInfo.find( vectChildren[i] )->second.an.tag )
		{
			bAllChildrenTagTwo = false;
			break;
		}
	}

	return	Clear(ni) &&
			!ni.an.marked &&
			bAllChildrenTagTwo &&
			!Is_Child(ni) &&
			(1 + Chldrn(ni).size() >= N(ni).size() );
}

bool CGraphBase::IsA4( const NodeInfo& ni ) const{

	bool bAllChildrenTagPlusTwo = true;
	std::vector<int> vectChildren = Chldrn( ni );
	for( size_t i=0; i<vectChildren.size(); i++ ){
		if ( (2+ni.an.tag) != _mapNodeInfo.find( vectChildren[i] )->second.an.tag )
		{
			bAllChildrenTagPlusTwo = false;
			break;
		}
	}

	bool bCheckTag = true;
	std::vector<int> vectParents = Parents(ni);
	if (vectParents.size() > 0 )
	{
		if ( ni.an.tag == 1 + _mapNodeInfo.find(vectParents[0])->second.an.tag )
			bCheckTag = true;
		else
			bCheckTag = false;
	}

	return	Clear(ni) &&
			ni.an.marked &&
			bAllChildrenTagPlusTwo &&
			Is_Child(ni) &&
			bCheckTag;
}

bool CGraphBase::IsA5( const NodeInfo& ni ) const{

	bool bAllNeighborsMarked = true;
	std::vector<int> vectNeighbors = N( ni );
	for ( size_t i=0; i<vectNeighbors.size(); i++ )
	{
		if ( _mapNodeInfo.find( vectNeighbors[i] )->second.an.marked )
		{
		}
		else
		{
			bAllNeighborsMarked = false;
			break;
		}
	}


	return	Clear(ni) &&
			ni.an.marked &&
			bAllNeighborsMarked &&
			!Is_Child(ni) &&
			!ni.an.is_leader;

}

bool CGraphBase::IsA6( const NodeInfo& ni ) const{
	return	Clear(ni) &&
			Finished(ni) &&
			!ni.an.finished;
}

void CGraphBase::A1( NodeInfo& ni ) const{
	ni.an.es		= 1;
	ni.an.marked	= false;
	ni.an.tag		= 0;
	ni.an.is_leader	= false;
	ni.an.finished	= false;
}

void CGraphBase::A2( NodeInfo& ni ) const{
	ni.an.es	+= 1;

	while( ni.an.es >= 3 )
		ni.an.es -= 3;
}

void CGraphBase::A3( NodeInfo& ni ) const{
	ni.an.marked	= true;
	ni.an.tag		= 1;
}

void CGraphBase::A4( NodeInfo& ni ) const{
	ni.an.tag	+= 1;

	while( ni.an.tag >= 5 )
		ni.an.tag -= 5;
}

void CGraphBase::A5( NodeInfo& ni ) const{
	ni.an.is_leader	= true;
}

void CGraphBase::A6( NodeInfo& ni ) const{
	ni.an.finished	= true;
}


bool CGraphBase::AtwleStep()
{
	bool bFinished = false;

	// Calculate what action can take ( A1, A2, A3, A4, A5 )

	std::map< int, std::string >	mapNodeAction;
	
	std::map< int, NodeInfo >::iterator itr;
	for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ )
	{
		if( IsA1( itr->second ) )
		{
			mapNodeAction[ itr->first ] = "A1";
		}
		else if( IsA2( itr->second ) )
		{
			mapNodeAction[ itr->first ] = "A2";
		}
		else if( IsA3( itr->second ) )
		{
			mapNodeAction[ itr->first ] = "A3";
		}
		else if( IsA4( itr->second ) )
		{
			mapNodeAction[ itr->first ] = "A4";
		}
		else if( IsA5( itr->second ) )
		{
			mapNodeAction[ itr->first ] = "A5";
		}
		else if( IsA6( itr->second ) )
		{
			mapNodeAction[ itr->first ] = "A6";
		}

	}

	CString strActionCheckResult = "Actions\r\n";
	std::map< int, std::string >::iterator itrAction;
	for ( itrAction = mapNodeAction.begin(); itrAction != mapNodeAction.end(); itrAction++ )
	{
		CString temp;
		temp.Format("[ %c -> %s] ", 'A' - 1 + itrAction->first, itrAction->second.c_str());

		strActionCheckResult = strActionCheckResult + temp;
	}
	if ( mapNodeAction.size() == 0 )
	{
		strActionCheckResult = "No action to take!"; 
	}

	AfxMessageBox( strActionCheckResult );


	// action
	
	for ( itrAction = mapNodeAction.begin(); itrAction != mapNodeAction.end(); itrAction++ )
	{
		if ( itrAction->second.compare( "A1" ) == 0 )
		{
			A1( _mapNodeInfo[itrAction->first] );
		}
		else if ( itrAction->second.compare( "A2" ) == 0 )
		{
			A2( _mapNodeInfo[itrAction->first] );
		}
		else if ( itrAction->second.compare( "A3" ) == 0 )
		{
			A3( _mapNodeInfo[itrAction->first] );
		}
		else if ( itrAction->second.compare( "A4" ) == 0 )
		{
			A4( _mapNodeInfo[itrAction->first] );
		}
		else if ( itrAction->second.compare( "A5" ) == 0 )
		{
			A5( _mapNodeInfo[itrAction->first] );
		}
		else if ( itrAction->second.compare( "A6" ) == 0 )
		{
			A6( _mapNodeInfo[itrAction->first] );
		}
	}


	return bFinished;
};

int CGraphBase::SetNodeClock( int index )
{
	if( _mapNodeInfo[index].schd.clock == -1 ){
		int maxClock = 0;
		for( size_t i=0; i<_mapNodeInfo[index]._outputs.size(); i++ )
		{
			int c = SetNodeClock( _mapNodeInfo[index]._outputs[i] );
			if( maxClock < (c+1) )
				maxClock = (c+1);
		}
		_mapNodeInfo[index].schd.clock = maxClock;
	}

	return _mapNodeInfo[index].schd.clock;
};

void CGraphBase::CalcClock()
{
	std::map< int, NodeInfo >::iterator itr;
	for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ )
	{
		itr->second.schd.clock = -1;
	}

	for( itr = _mapNodeInfo.begin(); itr != _mapNodeInfo.end(); itr++ )
	{
		SetNodeClock(itr->first);
	}
};
